//////////////////////////////////////////////
// Buffer.h
//
//////////////////////////////////////////////

/// Defines / Macros -------------------------

#pragma once

/// Includes ---------------------------------

// nkMemory
#include "../Dll/DllDefines.h"

// Standards
#include <array>
#include <cstring>
#include <vector>

/// Internals --------------------------------

namespace nkMemory
{
	struct BufferDataDescriptor
	{
		unsigned char* _data ;
		unsigned long long _size ;
	} ;
}

/// Class ------------------------------------

namespace nkMemory
{
	class DLL_MEMORY_EXPORT Buffer final
	{
		public :

			// Functions
			// Constructors, destructor
			Buffer () noexcept ;
			Buffer (unsigned long long size) noexcept ;
			Buffer (const unsigned char* data, unsigned long long size) noexcept ;
			Buffer (std::initializer_list<unsigned char> args) noexcept ;
			Buffer (const Buffer& other) noexcept ;
			Buffer (Buffer&& other) noexcept ;
			~Buffer () ;

			// Getters
			unsigned char* getData () const ;
			unsigned long long getSize () const ;
			bool empty () const ;
			unsigned char& front () ;
			const unsigned char& front () const ;
			unsigned char& back () ;
			const unsigned char& back () const ;
			unsigned char* begin () ;
			const unsigned char* begin () const ;
			unsigned char* end () ;
			const unsigned char* end () const ;

			// Management
			Buffer& clear () ;
			Buffer& resize (unsigned long long size) ;
			Buffer& append (unsigned char value) ;
			Buffer& erase (unsigned long long index, unsigned long long count = 1ull) ;
			BufferDataDescriptor relinquishDataOwnership () ;

			// Operators
			unsigned char& operator[] (unsigned long long index) ;
			const unsigned char& operator[] (unsigned long long index) const ;

			Buffer& operator= (const Buffer& other) noexcept ;
			Buffer& operator= (Buffer&& other) noexcept ;

		public :

			// Constructors templated
			template <typename T, std::size_t S>
			Buffer (const std::array<T, S>& array) noexcept
			:	Buffer ((unsigned char*)array.data(), array.size() * sizeof(T))
			{
				// Nothing to do
			}

			template <typename T>
			Buffer (const std::vector<T>& vec) noexcept
			:	Buffer ((unsigned char*)vec.data(), vec.size() * sizeof(T))
			{
				// Nothing to do
			}

		public :

			// Memory ownership taking constructors
			static Buffer createAndTakeMemory (unsigned char* data, unsigned long long size) ;

		private :

			// Attributes
			unsigned char* _data ;
			unsigned long long _size ;
	} ;
}